import javax.swing.JPanel;
import java.awt.Point;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;

public class GamePanel extends JPanel {

    private Minesweeper ms;

    private Point curPos = null;

    private static final Color UNCLEAN_COLOR      = new Color(0xA9, 0xA9, 0xA9, 0xFF);
    private static final Color CUR_SELECTED_COLOR = new Color(0xD3, 0xD3, 0xD3, 0xFF);
    private static final Color CLEANED_COLOR      = new Color(0xF5, 0xF5, 0xF5, 0xFF);
    private static final Color TIP_COLOR          = Color.BLACK;
    private static final Color MINE_COLOR         = Color.RED;
    private static final Color DOUBT_COLOR        = Color.WHITE;
    private static final Color DANGER_COLOR       = Color.RED;

    private static final short BOX_SIZE = 30;
    private static final byte BOX_GAP = 2;

    public GamePanel(Minesweeper ms) {
        super();
        setBackground(Color.lightGray);
        this.ms = ms;
        setSize(ms.W() * 32 + 2, ms.H() * 32 + 2);

        Font font = new Font(getFont().getFontName(), Font.PLAIN, 20);
        setFont(font);
    }

    public void MouseMotion(Point cursor){
        curPos = CurPointToGrid(cursor);
        repaint();
    }

    /**
     * 响应处理鼠标释放事件
     * @param cursor 鼠标位置
     * @param button 按下的鼠标按钮
     * @return 没啥动静返回0, 点到了地雷返回-1, 找出了所有地雷返回1
     */
    public int MouseReleased(Point cursor, int button){
        if(button == MouseEvent.BUTTON1) {
            var pos = CurPointToGrid(cursor);
            if(pos == null)
                return 0;
            
            var ret = ms.Clear(pos.y, pos.x);
            repaint();
            return ret;
        }
        else if(button == MouseEvent.BUTTON3) {
            var pos = CurPointToGrid(cursor);
            if(pos == null)
                return 0;

            var n = ms.Grid(pos.y, pos.x);
            if(n == Minesweeper.UNCLEAN || n == Minesweeper.DOUBT)
                ms.Mark(pos.y, pos.x, (byte) (n - 1));
            else if(n == Minesweeper.DANGER)
                ms.Mark(pos.y, pos.x, Minesweeper.UNCLEAN);

            repaint();
        }
        return 0;
    }

    private Point CurPointToGrid(Point cur){
        if (cur.x < BOX_GAP || cur.y < BOX_GAP || (cur.x - BOX_GAP) % (BOX_SIZE + BOX_GAP) > BOX_SIZE
                        || (cur.y - BOX_GAP) % (BOX_SIZE + BOX_GAP) > BOX_SIZE) {
            return null;
        }
                
        return new Point((cur.x - BOX_GAP) / (BOX_SIZE + BOX_GAP), (cur.y - BOX_GAP) / (BOX_SIZE + BOX_GAP));
    }

    private void DrawString(Graphics g, String str, int x, int y){
        var fm = g.getFontMetrics(g.getFont());
        x = x * (BOX_SIZE + BOX_GAP) + BOX_GAP + (BOX_SIZE  - fm.stringWidth(str)) / 2;
        y = (y + 1) * (BOX_SIZE + BOX_GAP) - BOX_GAP - (BOX_SIZE  - fm.getAscent()) / 2;
        g.drawString(str, x, y);
    }

    public void paint(Graphics g){
        super.paint(g);
        
        g.setColor(UNCLEAN_COLOR);
        for(int x = 0; x != ms.W(); ++x){
            for(int y = 0; y != ms.H(); ++y){
                var n = ms.Grid(y, x);
                var col = x * (BOX_SIZE + BOX_GAP) + BOX_GAP;
                var row = y * (BOX_SIZE + BOX_GAP) + BOX_GAP;
                switch(n)
                {
                    case Minesweeper.UNCLEAN:
                        g.setColor(UNCLEAN_COLOR);
                        g.fillRect(col, row, BOX_SIZE, BOX_SIZE);
                        break;
                    case Minesweeper.DANGER:
                        g.setColor(UNCLEAN_COLOR);
                        g.fillRect(col, row, BOX_SIZE, BOX_SIZE);
                        g.setColor(DANGER_COLOR);
                        DrawString(g, "!", x, y);
                        break;
                    case Minesweeper.DOUBT:
                        g.setColor(UNCLEAN_COLOR);
                        g.fillRect(col, row, BOX_SIZE, BOX_SIZE);
                        g.setColor(DOUBT_COLOR);
                        DrawString(g, "?", x, y);
                        break;
                    default:
                        g.setColor(CLEANED_COLOR);
                        g.fillRect(col, row, BOX_SIZE, BOX_SIZE);
                        if(n < 0){
                            g.setColor(MINE_COLOR);
                            DrawString(g, "X", x, y);
                        }
                        else if(n != 0){
                            g.setColor(TIP_COLOR);
                            DrawString(g, Byte.toString(n), x, y);
                        }
                }
            }
        }

        if(curPos != null){
            var n = ms.Grid(curPos.y, curPos.x);
            if(n < Minesweeper.CLEANED && n >= Minesweeper.DANGER){
                g.setColor(CUR_SELECTED_COLOR);
                g.fillRect(curPos.x * (BOX_SIZE + BOX_GAP) + BOX_GAP, curPos.y * (BOX_SIZE + BOX_GAP) + BOX_GAP, BOX_SIZE, BOX_SIZE);

                if(n == Minesweeper.DANGER){
                    g.setColor(DANGER_COLOR);
                    DrawString(g, "!", curPos.x, curPos.y);
                }else if(n == Minesweeper.DOUBT){
                    g.setColor(DOUBT_COLOR);
                    DrawString(g, "?", curPos.x, curPos.y);
                }
            }
        }
    }
}
